home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / newsgrp / group97b.txt / 000049_icon-group-sender _Tue Aug 5 09:41:32 1997.msg < prev    next >
Internet Message Format  |  2000-09-20  |  20KB

  1. Received: from kingfisher.CS.Arizona.EDU by cheltenham.cs.arizona.edu; Tue, 5 Aug 1997 12:21:53 MST
  2. Received: by kingfisher.CS.Arizona.EDU (5.65v4.0/1.1.8.2/08Nov94-0446PM)
  3.     id AA15282; Tue, 5 Aug 1997 12:21:52 -0700
  4. Message-Id: <s3e6f5a6.046@housmtp.oceaneering.com>
  5. X-Mailer: Novell GroupWise 4.1
  6. Date: Tue, 05 Aug 1997 09:41:32 -0500
  7. From: Charlie Hethcoat <CHETHCOA@oss.oceaneering.com>
  8. To: rogersba@rose-hulman.edu
  9. Cc: icon-group@cs.arizona.edu
  10. Subject: Icon Engineering examples? -Reply
  11. Mime-Version: 1.0
  12. Content-Type: text/plain
  13. Content-Disposition: inline
  14. Errors-To: icon-group-errors@cs.arizona.edu
  15. Status: RO
  16.  
  17. I meant to answer this a couple of weeks ago.  Sorry about the delay.
  18.  
  19. I am a Senior Engineer in the Analysis group at Oceaneering Space
  20. Systems.  We do a lot of stress and thermal analysis, and are heavily into
  21. finite element modelling of astronaut crew equipment.  While my job isn't
  22. primarily to program stuff, it is an activity I enjoy, and I occasionally need to
  23. do some ad-hoc things with Icon.
  24.  
  25. As one example, here is a program that computes 2-dimensional area
  26. properties of polygons of any size, with any number of embedded round
  27. holes.  The program is fairly common (I first saw it programmed for a HP-67
  28. calculator!), but nobody seems to think it should be a standard part of
  29. anybody's library.  Hence, when I need it, I always have to reimplement it.
  30.  
  31. In my Icon version, there is a nice ascii syntax for the input, it handles any
  32. number of vertices and holes, prints a neat little report, and generates a
  33. gnuplot input file and control file for plotting the shape.  Of course, you'll
  34. need gnuplot to plot it, or some plotting program that can handle gnuplot
  35. input.  There are some weaknesses in the input code that I need to improve
  36. (it isn't totally bulletproof), but the problem input syntax is so simple that
  37. there is almost no risk of screwing it up.
  38.  
  39. Some people here complain that it isn't a CAD program, and they would
  40. prefer to use, e. g. Autocad or Pro-Engineer.  Fine, let 'em, but I can be in
  41. and out of my little old Icon program, with the answers,  in less time than it
  42. takes them to log into Pro-E.  'Course, my program is only 2-D.  If 3-D is
  43. needed, you have to go elsewhere.  But then the descriptive geometry
  44. overhead becomes much more severe.
  45.  
  46. As you can see, Icon is a very nice language for general purpose mucking
  47. about with numerics.  The only problem I have noticed is a tendency of the
  48. left(), right(), and center() functions to truncate (rather than round properly)
  49. floating point numbers when printing them.  Internal accuracy, though, seems
  50. to be correct.
  51.  
  52. Warning!  This program requires command-line skills!!!   8^)  Maybe
  53. someone can modify it to use vib--my skills to do that are yet insufficient.  I'd
  54. like to see how my code can be adapted to that environment.
  55. _____________________________________________
  56.  
  57. # aprop.icn - Compute and plot area properties of 2D polygons w/holes
  58.  
  59. link "w:/software/icon/mylib/scantool"     # Update paths for your system
  60. link "w:/software/icon/mylib/numbtool"
  61. link "w:/software/icon/mylib/plotfns"
  62. link "basename"  # Std. Icon library
  63. link "real2int"     # for floor() and ceil()
  64. link "w:/software/icon/mylib/minmax"    # for minlist() and maxlist()
  65.  
  66. record holetype(x, y, d) # each hole gets location (x, y) and diameter d
  67.  
  68. global infile, outfile        # Text input and output
  69. global plotname, plotfile     # Plot data output
  70. global gnuname, gnufile       # Plot control output for Gnuplot
  71. global bname  # For access by plotting routines
  72. global x, y, holelist  # lists
  73. global i, n
  74. global xmin, xmax, xrange, ymin, ymax, yrange # For plotting ranges
  75.  
  76. global area, xcg, ycg
  77. global Ixx, Iyy, Ixy
  78. global Ixcg, Iycg, Ixycg
  79. global angle
  80. global Ixprime, Iyprime, Ixyprime
  81. global J
  82.  
  83. procedure main(args)
  84.  
  85.      static rcsid
  86.      initial {
  87.           rcsid := "$Id: aprop.icn 1.4 1996/12/18 21:16:39 Hethcoat Exp
  88. Hethcoat $"
  89.      }
  90.  
  91.      #
  92.      # $Log: aprop.icn $
  93.      # Revision 1.4  1996/12/18 21:16:39  Hethcoat
  94.      # Noticed a typo in the name of the rcsid variable.
  95.      #
  96.      # Revision 1.3  1996/10/10 22:35:27  Hethcoat
  97.      # Plotting enhancements:  Now generates all gnuplot data,
  98.      # scale factors for plotting now fully data-driven and are always in
  99.      # multiples of 0.5 world units per inch.
  100.      #
  101.      # Revision 1.2  1996/10/05 21:35:29  Hethcoat
  102.      # Merely added the RCS keyword strings.
  103.      #
  104.      #
  105.  
  106.      infile := &input
  107.      outfile := &output
  108.  
  109.      if *args = 0 then {  # A kluge for you to enjoy...
  110.           system("list.com aprop.hlp")
  111.           exit(0)
  112.      }
  113.  
  114.      # Looks for an input file in the form modelname.ext
  115.      # Generates output files in the same format.
  116.      bname := basename(args[1], ".")
  117.      infile := open(args[1], "r") | stop("Cannot open ", args[1], ".")
  118.      outname := bname || ".apo"
  119.      plotname := bname || ".dat"
  120.      gnuname := bname || ".gnu"
  121.      outfile := open(outname, "w") | stop("Cannot open ", basename, ".")
  122.  
  123.      # Setup
  124.  
  125.      holelist := []  # add holes as found
  126.      x := []
  127.      y := []
  128.      i := 0
  129.      write(outfile, center("Input Data Listing", 72, "-"))
  130.      write(outfile, )
  131.      # Input phase
  132.      while line := decomm(infile, outfile) do {
  133.           line ? {
  134.                if tab(match("hole")) then {
  135.                     ws(); xhole := num()
  136.                     ws(); yhole := num()
  137.                     ws(); dhole := num()
  138.                     put(holelist, holetype(xhole, yhole, dhole))
  139.                     next
  140.                }
  141.  
  142.                i +:= 1
  143.                put(x, num())
  144.                ws()
  145.                put(y, num())
  146.           }
  147.      }
  148.  
  149.      n := *x  # The number of points read, including any repeats.
  150.  
  151.      # Need ranges of the input data for plotting purposes:
  152.      xmin   := minlist(x)
  153.      xmax   := maxlist(x)
  154.      xrange := xmax - xmin
  155.      ymin   := minlist(y)
  156.      ymax   := maxlist(y)
  157.      yrange := ymax - ymin
  158.  
  159.      # Computations
  160.      do_numbers()
  161.  
  162.      # Report
  163.      do_report()
  164.  
  165.      # Plot control file
  166.      outplot1(xmin, xmax, ymin, ymax)
  167.  
  168.      # Data plot output
  169.      outplot2()
  170.  
  171.      exit(0)
  172.  
  173. end
  174.  
  175. # do_numbers - compute and print the detailed stuff
  176. procedure do_numbers()
  177.      area := xcg := ycg := Ixx := Iyy := Ixy := 0.0
  178.      n := *x
  179.      every i := (1 to n-1) do {
  180.           delta_x := x[i+1] - x[i]
  181.           sum_x   := x[i+1] + x[i]
  182.           delta_y := y[i+1] - y[i]
  183.           sum_y   := y[i+1] + y[i]
  184.           area +:= delta_y*sum_x
  185.           xcg +:= delta_y*(sum_x^2 + delta_x^2/3.)
  186.           ycg +:= delta_x*(sum_y^2 + delta_y^2/3.)
  187.           Ixx +:= delta_x*sum_y*(sum_y^2 + delta_y^2)
  188.           Iyy +:= delta_y*sum_x*(sum_x^2 + delta_x^2)
  189.           # Ixy is so big it has to be done in pieces:
  190.           term1 := x[i+1]*y[i] - x[i]*y[i+1]
  191.           term2 := x[i+1]^2 + x[i]^2
  192.           Ixy1 := delta_y^2*sum_x*(term2)/8.
  193.           Ixy2 := delta_y*(term1)*(term2 + x[i+1]*x[i] )/3.
  194.           Ixy3 := (term1)^2*sum_x/4.
  195.           if not wee(delta_x) then
  196.                Ixy +:= (Ixy1 + Ixy2 + Ixy3)/delta_x
  197.           # else there is no contribution when delta_x
  198.           # is zero.
  199.      }
  200.      area /:= -2.0
  201.      xcg /:= (-8.*area)
  202.      ycg /:= (8.*area)
  203.      Ixx /:= 24.
  204.      Iyy /:= (-24.)
  205.      # Ixy is OK as it comes out.
  206.  
  207.      # The above is correct before adding round holes.
  208.      # Now have to correct for holes found, if any:
  209.  
  210.      every hole := !holelist do {
  211.           holearea := -&pi*hole.d^2/4.0 # Note:  negative area for holes!!
  212.           holeIxx := -&pi*hole.d^4/64.  # also negative!!
  213.           holeIyy := holeIxx # by symmetry
  214.           holeIxy := 0.0  # also by symmetry
  215.           newarea := area + holearea # don't tamper with area just yet!
  216.           xcg := (xcg*area + holearea*hole.x)/newarea # updated x c.g.
  217.           ycg := (ycg*area + holearea*hole.y)/newarea
  218.           Ixx +:= (holeIxx + holearea*hole.y^2)
  219.           Iyy +:= (holeIyy + holearea*hole.x^2)
  220.           Ixy +:= (holeIxy + holearea*hole.x*hole.y)
  221.           area := newarea
  222.      }
  223.  
  224.      # Finish up with the final numbers:
  225.  
  226.      Ixcg := Ixx - area*ycg^2
  227.      Iycg := Iyy - area*xcg^2
  228.      Ixycg := Ixy - area*xcg*ycg
  229.      angle := 0.5*atan(-2.*Ixycg, Ixcg - Iycg)
  230.      c := cos(angle)
  231.      s := sin(angle)
  232.      s2 := sin(2.*angle)
  233.      c2 := cos(2.*angle)
  234.      Ixprime := Ixcg*c^2 + Iycg*s^2 - Ixycg*s2
  235.      Iyprime := Iycg*c^2 + Ixcg*s^2 + Ixycg*s2
  236.      J := Ixprime + Iyprime
  237.      Ixyprime := 0.5*(Ixcg - Iycg)*s2 + Ixycg*c2
  238.      return
  239. end
  240.  
  241. # do_report - print the report
  242. procedure do_report()
  243.      write(outfile, )
  244.      write(outfile, center("Area Properties Report", 72, "-"))
  245.      write(outfile, )
  246.      write(outfile, "Polygon:  ", n - 1, " points")
  247.      write(outfile, "Holes:  ", *holelist)
  248.      write(outfile, "area = ", area)
  249.      write(outfile, "xcg  = ", xcg)
  250.      write(outfile, "ycg  = ", ycg)
  251.      write(outfile, "Original axes:")
  252.      write(outfile, "Ixx  = ", Ixx)
  253.      write(outfile, "Iyy  = ", Iyy)
  254.      write(outfile, "Ixy  = ", Ixy)
  255.      write(outfile, "Centroidal axes (parallel to Original):")
  256.      write(outfile, "Ixxcg = ", Ixcg)
  257.      write(outfile, "Iyycg = ", Iycg)
  258.      write(outfile, "Ixycg = ",Ixycg)
  259.      write(outfile, "Principal axes (rotated from Centroidal):")
  260.      write(outfile, "angle = ", rtod(angle), " degrees")
  261.      write(outfile, "Ix'x' = ", Ixprime)
  262.      write(outfile, "Iy'y' = ", Iyprime)
  263.      write(outfile, "Ix'y' = ", Ixyprime)
  264.      write(outfile, "Polar Moment of Inertia:")
  265.      write(outfile, "J = ", J)
  266.      return
  267. end
  268.  
  269. # outplot1 - Output file (*.gnu) with plotting controls
  270. procedure outplot1(xmin, xmax, ymin, ymax)
  271.  
  272.      # Right now, this plots only to an hpljii at 150x150.  We'll
  273.      # improve it later.
  274.  
  275.      static wide, high, clear
  276.  
  277.      local xrange, yrange
  278.      local xbox, ybox
  279.      local xmini, xmaxi, ymini, ymaxi
  280.      local xsizei, ysizei
  281.      local xscale, yscale
  282.      local scale
  283.      local max_x, max_y
  284.  
  285.      initial {
  286.           # Need the actual plot area.
  287.           # These are correct for the HP Laserjet 4 Plus
  288.           # in portrait mode (so far!)
  289.           wide := 5.35
  290.           high := 6.06
  291.           clear := 0.5  # minimum clearance around the data
  292.      }
  293.  
  294.      # Imagine a box just enclosing the data:
  295.      xbox := xmax - xmin
  296.      ybox := ymax - ymin
  297.  
  298.      # Now find the next larger box with at least the stipulated clearance
  299.      # and with integer dimensions:
  300.      xmini := ceil(xmin - clear)
  301.      xmaxi := ceil(xmax + clear)
  302.      ymini := ceil(ymin - clear)
  303.      ymaxi := ceil(ymax + clear)
  304.  
  305.      # Get the size of that integer box:
  306.      xsizei := xmaxi - xmini
  307.      ysizei := ymaxi - ymini
  308.  
  309.      # Compute separate x and y scale factors for plotting:
  310.      xscale := xsizei/wide
  311.      yscale := ysizei/high
  312.  
  313.      # The plot will be made to equal x and y scales, so it has to be
  314.      # the larger of the two scales.  Furthermore, it would be convenient
  315.      # for the scale to be a nice number, i. e. positive multiples of 0.5.
  316.      scale := 0.5*ceil(2.0*maxlist([xscale, yscale]))
  317.  
  318.      # Now, get the plotting parameters in shape for use with the gnuplot
  319.      # xrange and yrange commands:
  320.  
  321.      max_x := xmini + scale*wide
  322.      max_y := ymini + scale*high
  323.  
  324.      gnufile := open(gnuname, "w") | stop("Cannot open ", gnuname, ".")
  325.      write(gnufile,"set data style lines")
  326.      write(gnufile,"set xrange [", xmini, ":", max_x, "]")
  327.      write(gnufile,"set yrange [", ymini, ":", max_y, "]")
  328.      write(gnufile,"set terminal hpljii 150")
  329.      write(gnufile,"set output '", bname || ".prn'")
  330.      write(gnufile,"plot '", plotname, " '")
  331.      write(gnufile,"exit")
  332. #    write(gnufile,"") PATTERN--KEEP!
  333.      close(gnufile)
  334.      return
  335. end
  336.  
  337. # outplot2 - Output file (*.dat) of results
  338. procedure outplot2()
  339.      local length
  340.  
  341.      plotfile := open(plotname, "w") | stop("Cannot open " || plotname || ".")
  342.      length := 1.25*minlist([xrange, yrange])
  343.  
  344.      # Plot the input (x, y) data:
  345.      comment("Plot file generated by aprop on " || &dateline)
  346.      comment("Cross section:  " || bname)
  347.      comment("")  # empty comment
  348.      comment("Polygon data:")
  349.      drawdata(x, y)
  350.      comment("Centroidal axes:")
  351.      drawcross(xcg, ycg, length, 0.0)
  352.      comment("Principal axes:")
  353.      drawcross(xcg, ycg, length, angle)
  354.      comment("End of data.")
  355.      close(plotfile)
  356.      return
  357. end
  358.  
  359. # drawdata - draw (x, y) list data
  360. procedure drawdata(x, y)
  361.      local i, hole
  362.      move(x[1], y[1])
  363.      every i := 2 to *x do
  364.           draw(x[i], y[i])
  365.      every hole := !holelist do {
  366.           comment("Hole:")
  367.           drawcircle(hole.x, hole.y, 0.5*hole.d)
  368.           comment("Crosshairs for preceding hole:")
  369.           drawcross(hole.x, hole.y, hole.d, 0.0)
  370.      }
  371.      return
  372. end
  373. ________________________________________
  374.  
  375. # numbtool.icn - basic numerical math aids (nothing too fancy)
  376. # Usage:  line w:\software\icon\mylib\numbtool
  377. # Author:      Charles L. Hethcoat III
  378. # Date:        September 14, 1996
  379.  
  380. # macheps - discern machine epsilon by test
  381. procedure macheps()
  382.      static eps
  383.      initial eps := 1.0
  384.      while 1.0 + eps > 1.0 do
  385.           eps *:= 0.5
  386.      # Comes out only when eps is indiscernible, i.e. makes
  387.      # no difference when added to 1.0.  This is more or less the
  388.      # definition of the machine epsilon.
  389.      return eps
  390. end
  391.  
  392. # wee - succeed if number is too "wee" (love that word) to divide by
  393. procedure wee(x)
  394.  
  395.      # Typical usage:  if not wee(x) then y := 1.0/x
  396.      # (wee() has to succeed, so that not wee fails, if x is wee.)
  397.      static thresh
  398.      initial thresh := 5.0*macheps()
  399.      if abs(x) < thresh then
  400.           return
  401.      # else fail
  402. end
  403. ______________________________________
  404.  
  405. # scantool.icn - simple token-scanning tools for use in various projects
  406. # Usage:  link w:\software\icon\mylib\scantool
  407. # Author:      Charles L. Hethcoat III
  408. # Date:        September 14, 1996
  409.  
  410. # id - scan an identifier
  411. procedure id()
  412.      static first, rest
  413.      initial {
  414.           first := &letters ++ '_'      # First chars in an identifier
  415.           rest := first ++ &digits      # Remaining ones
  416.      }
  417.      return scantok(first, rest)
  418. end
  419.  
  420. # num - scan and return the next number in &subject
  421. procedure num()
  422.      static first, rest
  423.      initial {
  424.           first := &digits ++ '+-.'    # First chars in a number
  425.           rest := first ++ 'e'        # Remaining ones
  426.      }
  427.      return real(scantok(first, rest))
  428. end
  429.  
  430. # scantok - scan tokens starting with first, finishing with rest
  431. procedure scantok(first, rest)
  432.      ws()
  433.      return tab(any(first)) || tab(many(rest)) | tab(any(first))
  434. end
  435.  
  436. # ws - skip white space (blanks and tabs)
  437. procedure ws()
  438.      tab(many(' \t'))
  439. end
  440.  
  441. # decomm - echo lines from infile and return decommented ones only
  442. procedure decomm(infile, outfile)
  443.      local line
  444.      while line := write(outfile, read(infile)) do
  445.           line ? {
  446.                ws()
  447.                if ='#' | pos(0) then next
  448.                return trim(tab(upto('#') | 0))
  449.           }
  450. end
  451. _____________________________________________________
  452. # minmax.icn:
  453. ############################################################################
  454. #
  455. #     These procedures return the maximum and minimum of a list containing
  456. #  any number of numeric arguments.  Modified by CLH from the library
  457. #  routine minmax, which uses variable-length argument lists.
  458. #
  459. ############################################################################
  460.  
  461. procedure minlist(L)
  462.    local minimum, n
  463.    minimum := L[1] | fail
  464.    every n := 2 to *L do
  465.       minimum >:= L[n]
  466.    return minimum
  467. end
  468.  
  469. procedure maxlist(L)
  470.    local maximum, n
  471.    maximum := L[1] | fail
  472.    every n := 2 to *L do
  473.       maximum <:= L[n]
  474.    return maximum
  475. end
  476. _____________________________________
  477. # plotfns.icn:
  478. # Plot routines that I can use in future programs.
  479. # All of the following "plot routines" just generate Gnuplot output!!
  480.  
  481. # drawcross - plot a cross with bar length L centered at (x, y) tilted theta
  482. procedure drawcross(x, y, L, theta)
  483.      centerline(x, y, L, theta)              # line
  484.      centerline(x, y, L, theta + 0.5*&pi)    # same line rotated +90 degrees
  485.      return
  486. end
  487.  
  488. # centerline - plot a line of length L centered at (x, y), tilted theta
  489. procedure centerline(x, y, L, theta)
  490.      local L2, dx, dy
  491.      L2 := 0.5*L
  492.      dx := L2*cos(theta)
  493.      dy := L2*sin(theta)
  494.      move(x - dx, y - dy)
  495.      draw(x, y)
  496.      draw(x + dx, y + dy)
  497.      return
  498. end
  499.  
  500. # drawcircle - plot a circle of radius r centered at (x, y)
  501. procedure drawcircle(xc, yc, r)
  502.      static n, deltheta
  503.      local i, theta, x, y, x1, y1
  504.      initial {
  505.           n := 16    # Number of points to draw
  506.           deltheta := 2.0*&pi/n
  507.      }
  508.      every i := 1 to n do {
  509.           theta := real(i - 1)*deltheta
  510.           x := xc + r*cos(theta)
  511.           y := yc + r*sin(theta)
  512.           if i = 1 then {
  513.                x1 := x; y1 := y  # Save 1st point for doing the last line.
  514.                move(x, y)  # and don't drag the pen.
  515.           }
  516.           else
  517.                draw(x, y)
  518.      }
  519.      draw(x1, y1) # Close the circle.
  520.      return
  521. end
  522.  
  523. # move - move to a new starting coordinate (x, y) for the next line
  524. procedure move(x, y)
  525.      write(plotfile) # Gnuplot starts a new line with a blank input line.
  526.      write(plotfile, x, " ", y)
  527.      return
  528. end
  529.  
  530. # draw - draw a line to final coordinate (x, y)
  531. procedure draw(x, y)
  532.      write(plotfile, x, " ", y)
  533.      return
  534. end
  535.  
  536. # comment - add a gnuplot comment line to the data
  537. procedure comment(line)
  538.      write(plotfile, "# ", line)
  539.      return
  540. end
  541.  
  542. _____________________________________
  543.  
  544. # aprop.inp - a right triangle with a rt. triangular hole & 2 round holes
  545.  
  546. # Sample input data
  547. # Note the comment convention:  From any '#' to the end of a line is ignored.
  548. # You may use comments in all your input files for documentation purposes.
  549.  
  550. # Start the outer triangle.  Move clockwise for areas:
  551.  
  552. # (X,Y) coordinate pairs:
  553.  
  554. 3.   1.
  555. 3.   7.
  556. 14.  7.
  557. 3.   1. # Closure on outer triangle--necessary!
  558.  
  559. # Polygonal holes are defined by moving to and fro along a "cut" line.
  560.  
  561. 4.   4. # Move along cut to inner triangle
  562.  
  563. # Polygonal holes are done the same way, except moving
  564. counterclockwise.
  565.  
  566. 9.   6. # Starts the inner triangle
  567. 4.   6.
  568. 4.   4. # Closure on inner triangle
  569. 3.   1. # Move outward on cut to final closure
  570.  
  571. # Finally, let's have two round holes:
  572.  
  573. #    X         Y         Diameter
  574.  
  575. hole 5.5       3.5       1.0
  576. hole 10.0      6.0       0.5
  577. _______________________________
  578.  
  579. That's it.  Good luck.  
  580.  
  581. Charles Hethcoat
  582.  
  583. >>> "Brian A. Rogers" <rogersba@rose-hulman.edu> 1997 Jul 24,
  584. 02:05pm >>>
  585.  Hi...
  586.  
  587. I'm looking for some examples of Icon programs that prvide some sort of
  588. engineering or science function.  From what I've read so far, it's a neat
  589. language.  I'd like to see someone using it, though.
  590.  
  591.  
  592. --
  593. ----------------------------------------------------------
  594. Brian A. Rogers
  595. Student Manager, Laptop Orientation
  596. Rose-Hulman Institute of Technology
  597. (812) 877-8034
  598. -----------------------------------------------------------
  599. "There are no problems, only solutions."
  600. Tron, 1982
  601. -----------------------------------------------------------
  602.  
  603.  
  604.  
  605.  
  606.  
  607.